{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9792da92-c185-4084-a925-0a407e5ce888",
   "metadata": {},
   "source": [
    "# Agent模块代码实战"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    " 核心思想是ReAct 推理+操作\n",
    "\n",
    "联网API获取：https://app.tavily.com/home"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "准备工作：\n",
    "pip install --upgrade langchain-openai tavily-python\n",
    "提前准备tavily_api_key: 到Tavily 官方网站注册获取API KEY\n",
    "Tavily Search 是一个专为人工智能体设计的搜索API，主要用于实时在线信息的集成。\n",
    "Tavily Search API 允许人工智能开发人员将他们的应用程序与互联网上的实时信息结合起来，这对于需要获取最新数据或执行复杂查询的AI应用来说非常有用。通过这个API，AI可以访问大量的在线信息，并以高效的方式检索和处理数据，从而为用户提供更准确、更及时的信息或服务。例如，如果代理需要回答一个大模型未训练的涉及最新事件的问题，它可以通过Tavily Search API联网来获取相关\n",
    "信息，然后将这些信息整合到其回答中。\n",
    "\n",
    "\n",
    "1.使用TavilySearchResults ，则需要提前到Tavily 官方网站注册获取API KEY\n",
    "2.使用SerpAPIWrapper 使用的是谷歌的搜索引擎，需要到https://serpapi.com/manage-api-key申请Google的API KEY\n"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 1 Self-ask with search 自我询问类型的Agent"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 1.联网搜索方式1： Tavily API（搜索API） + Fireworks APi （开源模型）\n",
    "下面样例中展示，Agent通过自我询问的方式查询互联网API获取答案\n",
    "准备工作：\n",
    "1.下面使用到了搜索引擎Tavily，需要到Tavily官网申请的API KEY\n",
    "2.下面使用到了Fireworks的模型需要到Fireworks.ai申请API KEY 配置到环境变量"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Program Files (x86)\\python3\\lib\\site-packages\\langchain_core\\_api\\deprecation.py:117: LangChainDeprecationWarning: The class `langchain_community.llms.fireworks.Fireworks` was deprecated in langchain-community 0.0.26 and will be removed in 0.2. An updated version of the class exists in the langchain-fireworks package and should be used instead. To use it run `pip install -U langchain-fireworks` and import as `from langchain_fireworks import Fireworks`.\n",
      "  warn_deprecated(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3m Yes.\n",
      "Follow up: Which NBA team won the championship last season?\u001B[0m\u001B[36;1m\u001B[1;3mAccording to the data provided, the Denver Nuggets won the NBA championship last season in 2022.\u001B[0m\u001B[32;1m\u001B[1;3m\n",
      "So the final answer is: Denver Nuggets\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'input': '上个赛季的NBA总冠军是哪支球队？', 'output': 'Denver Nuggets'}"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import os\n",
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, create_self_ask_with_search_agent\n",
    "from langchain_community.llms import Fireworks\n",
    "from langchain_community.tools.tavily_search import TavilyAnswer\n",
    "\n",
    "#需要申请搜索引擎Tavily的API KEY  （Tavily 专门为人工智能体设计了一款搜索 API）\n",
    "tools = [TavilyAnswer(max_results=1, name=\"Intermediate Answer\",tavily_api_key='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')]\n",
    "# 获取prompt\n",
    "prompt = hub.pull(\"hwchase17/self-ask-with-search\")\n",
    "\n",
    "# 选择大模型 需要申请Fireworks.ai的API KEY （Fireworks.ai 是一家提供开源模型API服务）\n",
    "llm = Fireworks(fireworks_api_key=os.environ['FIREWORKS_API_KEY'])\n",
    "\n",
    "#构建代理\n",
    "agent = create_self_ask_with_search_agent(llm, tools, prompt)\n",
    "#创建代理执行器\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "agent_executor.invoke(\n",
    "    {\"input\": \"上个赛季的NBA总冠军是哪支球队？\"}\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.联网搜索方式二： Google API（搜索API） + OpenAI APi （开源模型）\n",
    "下面样例中展示，Agent通过自我询问的方式查询互联网API获取答案\n",
    "准备工作：\n",
    "1.下面使用到了搜索引擎google，需要到google官网申请的API KEY\n",
    "https://developers.google.com/?hl=zh-cn"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "ename": "ValidationError",
     "evalue": "1 validation error for GoogleSearchResults\napi_wrapper\n  field required (type=value_error.missing)",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mValidationError\u001B[0m                           Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[2], line 10\u001B[0m\n\u001B[0;32m      7\u001B[0m llm \u001B[38;5;241m=\u001B[39m ChatOpenAI(temperature\u001B[38;5;241m=\u001B[39m\u001B[38;5;241m0\u001B[39m)\n\u001B[0;32m      8\u001B[0m \u001B[38;5;66;03m#需要申请对应搜索引擎的API KEY ;  https://serpapi.com/manage-api-key\u001B[39;00m\n\u001B[0;32m      9\u001B[0m \u001B[38;5;66;03m#google_api_key=os.environ['SERPAPI_API_KEY']\u001B[39;00m\n\u001B[1;32m---> 10\u001B[0m tools \u001B[38;5;241m=\u001B[39m [\u001B[43mGoogleSearchResults\u001B[49m\u001B[43m(\u001B[49m\u001B[43mgoogle_cse_id\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m122\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43mgoogle_api_key\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mos\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43menviron\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mSERPAPI_API_KEY\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m]\u001B[49m\u001B[43m)\u001B[49m]\n\u001B[0;32m     11\u001B[0m prompt \u001B[38;5;241m=\u001B[39m hub\u001B[38;5;241m.\u001B[39mpull(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mhwchase17/openai-tools-agent\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m     12\u001B[0m agent \u001B[38;5;241m=\u001B[39m create_openai_tools_agent(llm, tools, prompt)\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\langchain_core\\load\\serializable.py:120\u001B[0m, in \u001B[0;36mSerializable.__init__\u001B[1;34m(self, **kwargs)\u001B[0m\n\u001B[0;32m    119\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21m__init__\u001B[39m(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs: Any) \u001B[38;5;241m-\u001B[39m\u001B[38;5;241m>\u001B[39m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[1;32m--> 120\u001B[0m     \u001B[38;5;28msuper\u001B[39m()\u001B[38;5;241m.\u001B[39m\u001B[38;5;21m__init__\u001B[39m(\u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m    121\u001B[0m     \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_lc_kwargs \u001B[38;5;241m=\u001B[39m kwargs\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\pydantic\\v1\\main.py:341\u001B[0m, in \u001B[0;36mBaseModel.__init__\u001B[1;34m(__pydantic_self__, **data)\u001B[0m\n\u001B[0;32m    339\u001B[0m values, fields_set, validation_error \u001B[38;5;241m=\u001B[39m validate_model(__pydantic_self__\u001B[38;5;241m.\u001B[39m\u001B[38;5;18m__class__\u001B[39m, data)\n\u001B[0;32m    340\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m validation_error:\n\u001B[1;32m--> 341\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m validation_error\n\u001B[0;32m    342\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m    343\u001B[0m     object_setattr(__pydantic_self__, \u001B[38;5;124m'\u001B[39m\u001B[38;5;124m__dict__\u001B[39m\u001B[38;5;124m'\u001B[39m, values)\n",
      "\u001B[1;31mValidationError\u001B[0m: 1 validation error for GoogleSearchResults\napi_wrapper\n  field required (type=value_error.missing)"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, create_openai_tools_agent\n",
    "from langchain_community.tools.google_search import GoogleSearchResults\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(temperature=0)\n",
    "#需要申请对应搜索引擎的API KEY ;  https://serpapi.com/manage-api-key\n",
    "#google_api_key=os.environ['SERPAPI_API_KEY']\n",
    "tools = [GoogleSearchResults(google_cse_id=111111,google_api_key=os.environ['SERPAPI_API_KEY'])]\n",
    "prompt = hub.pull(\"hwchase17/openai-tools-agent\")\n",
    "agent = create_openai_tools_agent(llm, tools, prompt)\n",
    "\n",
    "# 创建代理执行器\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "agent_executor.invoke({\"input\": \"谁是现任美国总统?\"})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.联网搜索方式三： Tavily API（搜索API） + OpenAI APi （开源模型）\n",
    "下面样例中展示，Agent通过自我询问的方式查询互联网API获取答案\n",
    "准备工作：\n",
    "1.下面使用到了搜索引擎Tavily，需要到Tavily官网申请的API KEY"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3m\n",
      "Invoking: `tavily_search_results_json` with `{'query': '卡塔尔世界杯冠军球队'}`\n",
      "\n",
      "\n",
      "\u001B[0m\u001B[36;1m\u001B[1;3m[{'url': 'https://baike.baidu.com/item/2022年卡塔尔世界杯决赛/62470695', 'content': '2022年卡塔尔世界杯决赛，于2022年12月18日在卢赛尔体育场举行，以决出2022年卡塔尔世界杯冠军归属，对阵双方为阿根廷与法国。最终阿根廷队以7:5(点球大战4:2)击败卫冕冠军法国队，时隔36年再次捧起大力神杯。'}]\u001B[0m\u001B[32;1m\u001B[1;3m卡塔尔世界杯冠军球队是阿根廷队，他们在2022年的世界杯决赛中以点球大战4:2击败法国队，时隔36年再次捧起大力神杯。\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'input': '卡塔尔世界杯冠军球队是?',\n 'output': '卡塔尔世界杯冠军球队是阿根廷队，他们在2022年的世界杯决赛中以点球大战4:2击败法国队，时隔36年再次捧起大力神杯。'}"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, create_openai_tools_agent\n",
    "from langchain_community.tools.tavily_search import TavilySearchResults\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "#需要申请搜索引擎Tavily的API KEY\n",
    "tools = [TavilySearchResults(max_results=1,tavily_api_key= \"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\")]\n",
    "\n",
    "# Get the prompt to use - you can modify this!\n",
    "prompt = hub.pull(\"hwchase17/openai-tools-agent\")\n",
    "\n",
    "# Choose the LLM that will drive the agent\n",
    "# Only certain models support this\n",
    "llm = ChatOpenAI(model=\"gpt-3.5-turbo-1106\", temperature=0)\n",
    "\n",
    "# Construct the OpenAI Tools agent\n",
    "agent = create_openai_tools_agent(llm, tools, prompt)\n",
    "\n",
    "# Create an agent executor by passing in the agent and tools\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "agent_executor.invoke({\"input\": \"卡塔尔世界杯冠军球队是?\"})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 2. OpenAI functions"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.1 OpenAI functions代理方式"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, create_openai_functions_agent\n",
    "from langchain_community.tools.tavily_search import TavilySearchResults\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "#选择Tavily搜索引擎作为查询工具\n",
    "tools = [TavilySearchResults(max_results=1)]"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "data": {
      "text/plain": "[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template='You are a helpful assistant')),\n MessagesPlaceholder(variable_name='chat_history', optional=True),\n HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['input'], template='{input}')),\n MessagesPlaceholder(variable_name='agent_scratchpad')]"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#选择提示词\n",
    "prompt = hub.pull(\"hwchase17/openai-functions-agent\")\n",
    "prompt.messages"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [],
   "source": [
    "# 选择OpenAI的模型驱动代理\n",
    "llm = ChatOpenAI(model=\"gpt-3.5-turbo-1106\")\n",
    "\n",
    "# 构造 OpenAI Functions agent\n",
    "agent = create_openai_functions_agent(llm, tools, prompt)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3m\n",
      "Invoking: `tavily_search_results_json` with `{'query': 'LangChain'}`\n",
      "\n",
      "\n",
      "\u001B[0m\u001B[36;1m\u001B[1;3m[{'url': 'https://www.langchain.com/', 'content': 'Join Discord\\nContribute on GitHub\\n5.3M\\nMonthly Downloads\\n67k\\nGithub Stars\\n1800+\\nContributors\\n34k+\\nApps Powered\\nReady to build?\\nGo To Docs\\nGo To Docs\\nGo To Docs\\nContact Sales\\nContact Sales\\nContact Sales\\nProducts and use-cases\\nLangChain\\nLangSmith\\nRetrieval\\nAgents\\nInspiration\\nCode\\nGitHub\\nLangChain Hub\\nPython Docs\\nJS/TS Docs\\nSocial\\nTwitter\\nDiscord\\nBlog\\nLinkedIn\\nYouTube\\nTerms of Service\\nSign up for our newsletter\\nProducts and use-cases\\nLangChain\\nLangSmith\\nRetrieval\\nAgents\\nInspiration\\nCode\\nGitHub\\nLangChain Hub\\nPython Docs\\nJS/TS Docs\\nSocial\\nTwitter\\nDiscord\\nBlog\\nLinkedIn\\nYouTube\\nTerms of Service\\nSign up for our newsletter\\nProducts and use-cases\\nLangChain\\nLangSmith\\nRetrieval\\nAgents\\nInspiration\\nCode\\nGitHub\\nLangChain Hub\\nPython Docs\\nJS/TS Docs\\nSocial\\nTwitter\\nDiscord\\nBlog\\nLinkedIn\\nYouTube\\nTerms of Service\\nSign up for our newsletter Chatbots\\nQ&A Over Docs\\nSummarization\\nCopilots\\nWorkflow Automation\\nDocument Analysis\\nCustom Search\\nHarness the power–and wrangle the complexity– of LLMs\\nGet from proof-of-concept to production on one platform\\nRely on a set of tools built especially for non-deterministic models\\nLeverage new cognitive architectures and battle-tested orchestration\\nThanks to our contributors and partners for making LangChain awesome\\nWhen you build with LangChain, you build alongside a community of developers advancing the frontier of what’s possible with LLMs.\\n 🦜🔗 LangChain\\nLangSmith\\nLangServe\\nAgents\\nRetrieval\\nEvaluation\\nBlog\\nDocs\\n🦜🔗 LangChain\\n🦜🔗 LangChain\\nLangChain Expression Language makes it easy to create custom chains.\\n Go To Docs\\nGo To Docs\\nGo To Docs\\nContact Sales\\nglobal corporations, STARTUPS, and TINKERERS build with LangChain\\nglobal corporations, STARTUPS, and TINKERERS build with LangChain\\nglobal corporations, STARTUPS, and TINKERERS build with LangChain\\nA complete set of powerful building blocks\\nA complete set of powerful building blocks\\n Try it out here\\nGet your LLM application from prototype to production\\nGet your LLM application from prototype to production\\nBuild context-aware, reasoning applications with LangChain’s flexible abstractions and AI-first toolkit.\\n'}]\u001B[0m\u001B[32;1m\u001B[1;3mLangChain is a platform that offers a complete set of powerful building blocks for building context-aware, reasoning applications using flexible abstractions and an AI-first toolkit. It enables developers to leverage new cognitive architectures and battle-tested orchestration to harness the power of non-deterministic models, particularly Large Language Models (LLMs). LangChain provides tools for chatbots, Q&A over docs, summarization, copilots, workflow automation, document analysis, and custom search. It is used by global corporations, startups, and developers to build advanced applications with LLMs. If you'd like to learn more, you can visit their website [here](https://www.langchain.com/).\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'input': 'what is LangChain?',\n 'output': \"LangChain is a platform that offers a complete set of powerful building blocks for building context-aware, reasoning applications using flexible abstractions and an AI-first toolkit. It enables developers to leverage new cognitive architectures and battle-tested orchestration to harness the power of non-deterministic models, particularly Large Language Models (LLMs). LangChain provides tools for chatbots, Q&A over docs, summarization, copilots, workflow automation, document analysis, and custom search. It is used by global corporations, startups, and developers to build advanced applications with LLMs. If you'd like to learn more, you can visit their website [here](https://www.langchain.com/).\"}"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# #创建代理执行器\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)\n",
    "agent_executor.invoke({\"input\": \"what is LangChain?\"})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3mYour name is Bob.\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'input': \"what's my name?\",\n 'chat_history': [HumanMessage(content='hi! my name is bob'),\n  AIMessage(content='Hello Bob! How can I assist you today?')],\n 'output': 'Your name is Bob.'}"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### 使用聊天历史\n",
    "from langchain_core.messages import AIMessage, HumanMessage\n",
    "\n",
    "agent_executor.invoke(\n",
    "    {\n",
    "        \"input\": \"what's my name?\",\n",
    "        \"chat_history\": [\n",
    "            HumanMessage(content=\"hi! my name is bob\"),\n",
    "            AIMessage(content=\"Hello Bob! How can I assist you today?\"),\n",
    "        ],\n",
    "    }\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 3. 自定义Agent"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.1.定义LLM"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "llm = ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.2.自定义处理工具"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "outputs": [
    {
     "data": {
      "text/plain": "3"
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.agents import tool\n",
    "\n",
    "@tool\n",
    "def get_word_length(word: str) -> int:\n",
    "    \"\"\"Returns the length of a word.\"\"\"\n",
    "    return len(word)\n",
    "\n",
    "\n",
    "get_word_length.invoke(\"abc\")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "outputs": [],
   "source": [
    "tools = [get_word_length]"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.3.创建prompt"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "outputs": [],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder\n",
    "\n",
    "prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"You are very powerful assistant, but don't know current events\", ),\n",
    "        (\"user\", \"{input}\"),\n",
    "        MessagesPlaceholder(variable_name=\"agent_scratchpad\"),\n",
    "    ]\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.4.绑定工具到LLM"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "outputs": [],
   "source": [
    "llm_with_tools = llm.bind_tools(tools)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.5.创建Agent"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "outputs": [],
   "source": [
    "from langchain.agents.format_scratchpad.openai_tools import (\n",
    "    format_to_openai_tool_messages,\n",
    ")\n",
    "from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser\n",
    "\n",
    "agent = (\n",
    "    {\n",
    "        \"input\": lambda x: x[\"input\"],\n",
    "        \"agent_scratchpad\": lambda x: format_to_openai_tool_messages(\n",
    "            x[\"intermediate_steps\"]\n",
    "        ),\n",
    "    }\n",
    "    | prompt\n",
    "    | llm_with_tools\n",
    "    | OpenAIToolsAgentOutputParser()\n",
    ")\n"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 3.6.构建AgentExecutor 再调用执行"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor\n",
    "\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n",
      "\u001B[32;1m\u001B[1;3m\n",
      "Invoking: `get_word_length` with `{'word': 'eudca'}`\n",
      "\n",
      "\n",
      "\u001B[0m\u001B[36;1m\u001B[1;3m5\u001B[0m\u001B[32;1m\u001B[1;3mThe word \"eudca\" has 5 letters.\u001B[0m\n",
      "\n",
      "\u001B[1m> Finished chain.\u001B[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": "[{'actions': [OpenAIToolAgentAction(tool='get_word_length', tool_input={'word': 'eudca'}, log=\"\\nInvoking: `get_word_length` with `{'word': 'eudca'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_AzluXlWFt8xvgOAZRuHJ3Vwq', 'function': {'arguments': '{\"word\":\"eudca\"}', 'name': 'get_word_length'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'})], tool_call_id='call_AzluXlWFt8xvgOAZRuHJ3Vwq')],\n  'messages': [AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_AzluXlWFt8xvgOAZRuHJ3Vwq', 'function': {'arguments': '{\"word\":\"eudca\"}', 'name': 'get_word_length'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'})]},\n {'steps': [AgentStep(action=OpenAIToolAgentAction(tool='get_word_length', tool_input={'word': 'eudca'}, log=\"\\nInvoking: `get_word_length` with `{'word': 'eudca'}`\\n\\n\\n\", message_log=[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_AzluXlWFt8xvgOAZRuHJ3Vwq', 'function': {'arguments': '{\"word\":\"eudca\"}', 'name': 'get_word_length'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'})], tool_call_id='call_AzluXlWFt8xvgOAZRuHJ3Vwq'), observation=5)],\n  'messages': [FunctionMessage(content='5', name='get_word_length')]},\n {'output': 'The word \"eudca\" has 5 letters.',\n  'messages': [AIMessage(content='The word \"eudca\" has 5 letters.')]}]"
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(agent_executor.stream({\"input\": \"How many letters in the word eudca\"}))"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 4. Stream流式操作"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 比如下面这道题：猫藏身的地方有哪些物品\n",
    "需要2个工具，1.先找到猫藏身的地方，2.再确认藏身的地方有哪些物品"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import AgentExecutor, create_openai_tools_agent\n",
    "from langchain.tools import tool\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "model = ChatOpenAI(temperature=0, streaming=True)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "outputs": [],
   "source": [
    "import random\n",
    "\n",
    "\n",
    "@tool\n",
    "async def where_cat_is_hiding() -> str:\n",
    "    \"\"\"Where is the cat hiding right now?\"\"\"\n",
    "    return random.choice([\"under the bed\", \"on the shelf\"])\n",
    "\n",
    "\n",
    "@tool\n",
    "async def get_items(place: str) -> str:\n",
    "    \"\"\"Use this tool to look up which items are in the given place.\"\"\"\n",
    "    if \"bed\" in place:  # For under the bed\n",
    "        return \"socks, shoes and dust bunnies\"\n",
    "    if \"shelf\" in place:  # For 'shelf'\n",
    "        return \"books, penciles and pictures\"\n",
    "    else:  # if the agent decides to ask about a different place\n",
    "        return \"cat snacks\""
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "outputs": [
    {
     "data": {
      "text/plain": "'under the bed'"
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#方法调用测试\n",
    "await where_cat_is_hiding.ainvoke({})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "outputs": [
    {
     "data": {
      "text/plain": "'books, penciles and pictures'"
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#方法调用测试\n",
    "await get_items.ainvoke({\"place\": \"shelf\"})"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "outputs": [],
   "source": [
    "# Get the prompt to use - you can modify this!\n",
    "prompt = hub.pull(\"hwchase17/openai-tools-agent\")\n",
    "# print(prompt.messages) -- to see the prompt\n",
    "tools = [get_items, where_cat_is_hiding]\n",
    "agent = create_openai_tools_agent(\n",
    "    model.with_config({\"tags\": [\"agent_llm\"]}), tools, prompt\n",
    ")\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools).with_config(\n",
    "    {\"run_name\": \"Agent\"}\n",
    ")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "------\n",
      "{'actions': [...], 'messages': [...]}\n",
      "------\n",
      "{'messages': [...], 'steps': [...]}\n",
      "------\n",
      "{'actions': [...], 'messages': [...]}\n",
      "------\n",
      "{'messages': [...], 'steps': [...]}\n",
      "------\n",
      "{'messages': [...],\n",
      " 'output': 'The items located where the cat is hiding (on the shelf) are '\n",
      "           'books, pencils, and pictures.'}\n"
     ]
    }
   ],
   "source": [
    "# Note: We use `pprint` to print only to depth 1, it makes it easier to see the output from a high level, before digging in.\n",
    "import pprint\n",
    "\n",
    "chunks = []\n",
    "#异步地从agent_executor.astream()获取数据块\n",
    "async for chunk in agent_executor.astream({\"input\": \"what's items are located where the cat is hiding?\"}):\n",
    "    chunks.append(chunk)\n",
    "    print(\"------\")\n",
    "    pprint.pprint(chunk, depth=1)\n",
    "\n",
    "#它看起来像这样：\n",
    "#动作输出actions\n",
    "#观测输出steps\n",
    "#动作输出actions\n",
    "#观测输出steps\n",
    "#...（继续直到达到目标）...\n",
    "#然后，如果达到最终目标，智能体将输出最终答案。"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_lCJicoLUxyNbVzzAkghNHu7o', 'function': {'arguments': '{}', 'name': 'where_cat_is_hiding'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'})]\n",
      "[FunctionMessage(content='on the shelf', name='where_cat_is_hiding')]\n",
      "[AIMessageChunk(content='', additional_kwargs={'tool_calls': [{'index': 0, 'id': 'call_9jsmlG4dhjTKuQQotvZFJjrX', 'function': {'arguments': '{\"place\":\"on the shelf\"}', 'name': 'get_items'}, 'type': 'function'}]}, response_metadata={'finish_reason': 'tool_calls'})]\n",
      "[FunctionMessage(content='books, penciles and pictures', name='get_items')]\n",
      "[AIMessage(content='The items located where the cat is hiding (on the shelf) are books, pencils, and pictures.')]\n"
     ]
    }
   ],
   "source": [
    "for chunk in chunks:\n",
    "    print(chunk[\"messages\"])"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Calling Tool: `where_cat_is_hiding` with input `{}`\n",
      "---\n",
      "Tool Result: `on the shelf`\n",
      "---\n",
      "Calling Tool: `get_items` with input `{'place': 'on the shelf'}`\n",
      "---\n",
      "Tool Result: `books, penciles and pictures`\n",
      "---\n",
      "Final Output: The items located where the cat is hiding (on the shelf) are books, pencils, and pictures.\n",
      "---\n"
     ]
    }
   ],
   "source": [
    "#查看整个处理流程中的行动、观察的过程\n",
    "async for chunk in agent_executor.astream(\n",
    "    {\"input\": \"what's items are located where the cat is hiding?\"}\n",
    "):\n",
    "    # Agent Action\n",
    "    if \"actions\" in chunk:\n",
    "        for action in chunk[\"actions\"]:\n",
    "            print(f\"Calling Tool: `{action.tool}` with input `{action.tool_input}`\")\n",
    "    # Observation\n",
    "    elif \"steps\" in chunk:\n",
    "        for step in chunk[\"steps\"]:\n",
    "            print(f\"Tool Result: `{step.observation}`\")\n",
    "    # Final result\n",
    "    elif \"output\" in chunk:\n",
    "        print(f'Final Output: {chunk[\"output\"]}')\n",
    "    else:\n",
    "        raise ValueError()\n",
    "    print(\"---\")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Starting agent: Agent with input: {'input': 'where is the cat hiding? what items are in that location?'}\n",
      "--\n",
      "Starting tool: where_cat_is_hiding with inputs: {}\n",
      "Done tool: where_cat_is_hiding\n",
      "Tool output was: on the shelf\n",
      "--\n",
      "--\n",
      "Starting tool: get_items with inputs: {'place': 'on the shelf'}\n",
      "Done tool: get_items\n",
      "Tool output was: books, penciles and pictures\n",
      "--\n",
      "The| cat| is| hiding| on| the| shelf|.| In| that| location|,| you| can| find| books|,| pencils|,| and| pictures|.|\n",
      "--\n",
      "Done agent: Agent with output: The cat is hiding on the shelf. In that location, you can find books, pencils, and pictures.\n"
     ]
    }
   ],
   "source": [
    "#查看整个处理流程中的事件处理过程\n",
    "async for event in agent_executor.astream_events(\n",
    "    {\"input\": \"where is the cat hiding? what items are in that location?\"},\n",
    "    version=\"v1\",\n",
    "):\n",
    "    kind = event[\"event\"]\n",
    "    if kind == \"on_chain_start\":\n",
    "        if (\n",
    "            event[\"name\"] == \"Agent\"\n",
    "        ):  # Was assigned when creating the agent with `.with_config({\"run_name\": \"Agent\"})`\n",
    "            print(\n",
    "                f\"Starting agent: {event['name']} with input: {event['data'].get('input')}\"\n",
    "            )\n",
    "    elif kind == \"on_chain_end\":\n",
    "        if (\n",
    "            event[\"name\"] == \"Agent\"\n",
    "        ):  # Was assigned when creating the agent with `.with_config({\"run_name\": \"Agent\"})`\n",
    "            print()\n",
    "            print(\"--\")\n",
    "            print(\n",
    "                f\"Done agent: {event['name']} with output: {event['data'].get('output')['output']}\"\n",
    "            )\n",
    "    if kind == \"on_chat_model_stream\":\n",
    "        content = event[\"data\"][\"chunk\"].content\n",
    "        if content:\n",
    "            # Empty content in the context of OpenAI means\n",
    "            # that the model is asking for a tool to be invoked.\n",
    "            # So we only print non-empty content\n",
    "            print(content, end=\"|\")\n",
    "    elif kind == \"on_tool_start\":\n",
    "        print(\"--\")\n",
    "        print(\n",
    "            f\"Starting tool: {event['name']} with inputs: {event['data'].get('input')}\"\n",
    "        )\n",
    "    elif kind == \"on_tool_end\":\n",
    "        print(f\"Done tool: {event['name']}\")\n",
    "        print(f\"Tool output was: {event['data'].get('output')}\")\n",
    "        print(\"--\")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5. iterator迭代操作"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "markdown",
   "source": [
    "###查找3个质数，并计算他们的乘积\n",
    "%pip install --upgrade --quiet  numexpr"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType, initialize_agent\n",
    "from langchain.chains import LLMMathChain\n",
    "from langchain_core.pydantic_v1 import BaseModel, Field\n",
    "from langchain_core.tools import Tool\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "# 目前只有 GPT-4 才支持这个智能化的处理过程，知道最终需要调用计算器进行计算\n",
    "llm = ChatOpenAI(temperature=0, model=\"gpt-4\")\n",
    "llm_math_chain = LLMMathChain.from_llm(llm=llm, verbose=True)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "outputs": [],
   "source": [
    "primes = {998: 7901, 999: 7907, 1000: 7919}\n",
    "\n",
    "\n",
    "class CalculatorInput(BaseModel):\n",
    "    question: str = Field()\n",
    "\n",
    "\n",
    "class PrimeInput(BaseModel):\n",
    "    n: int = Field()\n",
    "\n",
    "\n",
    "def is_prime(n: int) -> bool:\n",
    "    if n <= 1 or (n % 2 == 0 and n > 2):\n",
    "        return False\n",
    "    for i in range(3, int(n**0.5) + 1, 2):\n",
    "        if n % i == 0:\n",
    "            return False\n",
    "    return True\n",
    "\n",
    "\n",
    "def get_prime(n: int, primes: dict = primes) -> str:\n",
    "    return str(primes.get(int(n)))\n",
    "\n",
    "\n",
    "async def aget_prime(n: int, primes: dict = primes) -> str:\n",
    "    return str(primes.get(int(n)))\n",
    "\n",
    "\n",
    "tools = [\n",
    "    Tool(\n",
    "        name=\"GetPrime\",\n",
    "        func=get_prime,\n",
    "        description=\"A tool that returns the `n`th prime number\",\n",
    "        args_schema=PrimeInput,\n",
    "        coroutine=aget_prime,\n",
    "    ),\n",
    "    Tool.from_function(\n",
    "        func=llm_math_chain.run,\n",
    "        name=\"Calculator\",\n",
    "        description=\"Useful for when you need to compute mathematical expressions\",\n",
    "        args_schema=CalculatorInput,\n",
    "        coroutine=llm_math_chain.arun,\n",
    "    ),\n",
    "]"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "outputs": [
    {
     "ename": "ConnectionError",
     "evalue": "('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mConnectionResetError\u001B[0m                      Traceback (most recent call last)",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:793\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001B[0m\n\u001B[0;32m    792\u001B[0m \u001B[38;5;66;03m# Make the request on the HTTPConnection object\u001B[39;00m\n\u001B[1;32m--> 793\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_make_request(\n\u001B[0;32m    794\u001B[0m     conn,\n\u001B[0;32m    795\u001B[0m     method,\n\u001B[0;32m    796\u001B[0m     url,\n\u001B[0;32m    797\u001B[0m     timeout\u001B[38;5;241m=\u001B[39mtimeout_obj,\n\u001B[0;32m    798\u001B[0m     body\u001B[38;5;241m=\u001B[39mbody,\n\u001B[0;32m    799\u001B[0m     headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m    800\u001B[0m     chunked\u001B[38;5;241m=\u001B[39mchunked,\n\u001B[0;32m    801\u001B[0m     retries\u001B[38;5;241m=\u001B[39mretries,\n\u001B[0;32m    802\u001B[0m     response_conn\u001B[38;5;241m=\u001B[39mresponse_conn,\n\u001B[0;32m    803\u001B[0m     preload_content\u001B[38;5;241m=\u001B[39mpreload_content,\n\u001B[0;32m    804\u001B[0m     decode_content\u001B[38;5;241m=\u001B[39mdecode_content,\n\u001B[0;32m    805\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mresponse_kw,\n\u001B[0;32m    806\u001B[0m )\n\u001B[0;32m    808\u001B[0m \u001B[38;5;66;03m# Everything went great!\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:491\u001B[0m, in \u001B[0;36mHTTPConnectionPool._make_request\u001B[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001B[0m\n\u001B[0;32m    490\u001B[0m         new_e \u001B[38;5;241m=\u001B[39m _wrap_proxy_error(new_e, conn\u001B[38;5;241m.\u001B[39mproxy\u001B[38;5;241m.\u001B[39mscheme)\n\u001B[1;32m--> 491\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m new_e\n\u001B[0;32m    493\u001B[0m \u001B[38;5;66;03m# conn.request() calls http.client.*.request, not the method in\u001B[39;00m\n\u001B[0;32m    494\u001B[0m \u001B[38;5;66;03m# urllib3.request. It also calls makefile (recv) on the socket.\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:467\u001B[0m, in \u001B[0;36mHTTPConnectionPool._make_request\u001B[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001B[0m\n\u001B[0;32m    466\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 467\u001B[0m     \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_validate_conn\u001B[49m\u001B[43m(\u001B[49m\u001B[43mconn\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    468\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (SocketTimeout, BaseSSLError) \u001B[38;5;28;01mas\u001B[39;00m e:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:1099\u001B[0m, in \u001B[0;36mHTTPSConnectionPool._validate_conn\u001B[1;34m(self, conn)\u001B[0m\n\u001B[0;32m   1098\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m conn\u001B[38;5;241m.\u001B[39mis_closed:\n\u001B[1;32m-> 1099\u001B[0m     \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mconnect\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1101\u001B[0m \u001B[38;5;66;03m# TODO revise this, see https://github.com/urllib3/urllib3/issues/2791\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connection.py:653\u001B[0m, in \u001B[0;36mHTTPSConnection.connect\u001B[1;34m(self)\u001B[0m\n\u001B[0;32m    651\u001B[0m server_hostname_rm_dot \u001B[38;5;241m=\u001B[39m server_hostname\u001B[38;5;241m.\u001B[39mrstrip(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m.\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m--> 653\u001B[0m sock_and_verified \u001B[38;5;241m=\u001B[39m \u001B[43m_ssl_wrap_socket_and_match_hostname\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    654\u001B[0m \u001B[43m    \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    655\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcert_reqs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcert_reqs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    656\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    657\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_minimum_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_minimum_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    658\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_maximum_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_maximum_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    659\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_certs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_certs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    660\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_dir\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_cert_dir\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    661\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_data\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_cert_data\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    662\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcert_file\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcert_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    663\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_file\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mkey_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    664\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_password\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mkey_password\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    665\u001B[0m \u001B[43m    \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname_rm_dot\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    666\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_context\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    667\u001B[0m \u001B[43m    \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    668\u001B[0m \u001B[43m    \u001B[49m\u001B[43massert_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43massert_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    669\u001B[0m \u001B[43m    \u001B[49m\u001B[43massert_fingerprint\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43massert_fingerprint\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    670\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    671\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msock \u001B[38;5;241m=\u001B[39m sock_and_verified\u001B[38;5;241m.\u001B[39msocket\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connection.py:806\u001B[0m, in \u001B[0;36m_ssl_wrap_socket_and_match_hostname\u001B[1;34m(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)\u001B[0m\n\u001B[0;32m    804\u001B[0m         server_hostname \u001B[38;5;241m=\u001B[39m normalized\n\u001B[1;32m--> 806\u001B[0m ssl_sock \u001B[38;5;241m=\u001B[39m \u001B[43mssl_wrap_socket\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    807\u001B[0m \u001B[43m    \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    808\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkeyfile\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mkey_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    809\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcertfile\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcert_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    810\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_password\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mkey_password\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    811\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_certs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_certs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    812\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_dir\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_cert_dir\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    813\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_data\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_cert_data\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    814\u001B[0m \u001B[43m    \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    815\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcontext\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    816\u001B[0m \u001B[43m    \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    817\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    819\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\ssl_.py:465\u001B[0m, in \u001B[0;36mssl_wrap_socket\u001B[1;34m(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)\u001B[0m\n\u001B[0;32m    463\u001B[0m     \u001B[38;5;28;01mpass\u001B[39;00m\n\u001B[1;32m--> 465\u001B[0m ssl_sock \u001B[38;5;241m=\u001B[39m \u001B[43m_ssl_wrap_socket_impl\u001B[49m\u001B[43m(\u001B[49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontext\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    466\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m ssl_sock\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\ssl_.py:509\u001B[0m, in \u001B[0;36m_ssl_wrap_socket_impl\u001B[1;34m(sock, ssl_context, tls_in_tls, server_hostname)\u001B[0m\n\u001B[0;32m    507\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m SSLTransport(sock, ssl_context, server_hostname)\n\u001B[1;32m--> 509\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mwrap_socket\u001B[49m\u001B[43m(\u001B[49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:513\u001B[0m, in \u001B[0;36mSSLContext.wrap_socket\u001B[1;34m(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)\u001B[0m\n\u001B[0;32m    507\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrap_socket\u001B[39m(\u001B[38;5;28mself\u001B[39m, sock, server_side\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[0;32m    508\u001B[0m                 do_handshake_on_connect\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[0;32m    509\u001B[0m                 suppress_ragged_eofs\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[0;32m    510\u001B[0m                 server_hostname\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, session\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m    511\u001B[0m     \u001B[38;5;66;03m# SSLSocket class handles server_hostname encoding before it calls\u001B[39;00m\n\u001B[0;32m    512\u001B[0m     \u001B[38;5;66;03m# ctx._wrap_socket()\u001B[39;00m\n\u001B[1;32m--> 513\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msslsocket_class\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_create\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    514\u001B[0m \u001B[43m        \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    515\u001B[0m \u001B[43m        \u001B[49m\u001B[43mserver_side\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_side\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    516\u001B[0m \u001B[43m        \u001B[49m\u001B[43mdo_handshake_on_connect\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mdo_handshake_on_connect\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    517\u001B[0m \u001B[43m        \u001B[49m\u001B[43msuppress_ragged_eofs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msuppress_ragged_eofs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    518\u001B[0m \u001B[43m        \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    519\u001B[0m \u001B[43m        \u001B[49m\u001B[43mcontext\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[0;32m    520\u001B[0m \u001B[43m        \u001B[49m\u001B[43msession\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msession\u001B[49m\n\u001B[0;32m    521\u001B[0m \u001B[43m    \u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:1071\u001B[0m, in \u001B[0;36mSSLSocket._create\u001B[1;34m(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)\u001B[0m\n\u001B[0;32m   1070\u001B[0m             \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdo_handshake_on_connect should not be specified for non-blocking sockets\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m-> 1071\u001B[0m         \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdo_handshake\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1072\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (\u001B[38;5;167;01mOSError\u001B[39;00m, \u001B[38;5;167;01mValueError\u001B[39;00m):\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:1342\u001B[0m, in \u001B[0;36mSSLSocket.do_handshake\u001B[1;34m(self, block)\u001B[0m\n\u001B[0;32m   1341\u001B[0m         \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msettimeout(\u001B[38;5;28;01mNone\u001B[39;00m)\n\u001B[1;32m-> 1342\u001B[0m     \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_sslobj\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdo_handshake\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1343\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n",
      "\u001B[1;31mConnectionResetError\u001B[0m: [WinError 10054] 远程主机强迫关闭了一个现有的连接。",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mProtocolError\u001B[0m                             Traceback (most recent call last)",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\adapters.py:486\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[0;32m    485\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 486\u001B[0m     resp \u001B[38;5;241m=\u001B[39m \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43murlopen\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    487\u001B[0m \u001B[43m        \u001B[49m\u001B[43mmethod\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    488\u001B[0m \u001B[43m        \u001B[49m\u001B[43murl\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    489\u001B[0m \u001B[43m        \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    490\u001B[0m \u001B[43m        \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    491\u001B[0m \u001B[43m        \u001B[49m\u001B[43mredirect\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[0;32m    492\u001B[0m \u001B[43m        \u001B[49m\u001B[43massert_same_host\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[0;32m    493\u001B[0m \u001B[43m        \u001B[49m\u001B[43mpreload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[0;32m    494\u001B[0m \u001B[43m        \u001B[49m\u001B[43mdecode_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43;01mFalse\u001B[39;49;00m\u001B[43m,\u001B[49m\n\u001B[0;32m    495\u001B[0m \u001B[43m        \u001B[49m\u001B[43mretries\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mmax_retries\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    496\u001B[0m \u001B[43m        \u001B[49m\u001B[43mtimeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtimeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    497\u001B[0m \u001B[43m        \u001B[49m\u001B[43mchunked\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mchunked\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    498\u001B[0m \u001B[43m    \u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    500\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (ProtocolError, \u001B[38;5;167;01mOSError\u001B[39;00m) \u001B[38;5;28;01mas\u001B[39;00m err:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:847\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001B[0m\n\u001B[0;32m    845\u001B[0m     new_e \u001B[38;5;241m=\u001B[39m ProtocolError(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mConnection aborted.\u001B[39m\u001B[38;5;124m\"\u001B[39m, new_e)\n\u001B[1;32m--> 847\u001B[0m retries \u001B[38;5;241m=\u001B[39m \u001B[43mretries\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mincrement\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    848\u001B[0m \u001B[43m    \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43merror\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mnew_e\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_pool\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_stacktrace\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msys\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexc_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m[\u001B[49m\u001B[38;5;241;43m2\u001B[39;49m\u001B[43m]\u001B[49m\n\u001B[0;32m    849\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    850\u001B[0m retries\u001B[38;5;241m.\u001B[39msleep()\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\retry.py:470\u001B[0m, in \u001B[0;36mRetry.increment\u001B[1;34m(self, method, url, response, error, _pool, _stacktrace)\u001B[0m\n\u001B[0;32m    469\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m read \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mFalse\u001B[39;00m \u001B[38;5;129;01mor\u001B[39;00m method \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m \u001B[38;5;129;01mor\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_is_method_retryable(method):\n\u001B[1;32m--> 470\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[43mreraise\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;28;43mtype\u001B[39;49m\u001B[43m(\u001B[49m\u001B[43merror\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43merror\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_stacktrace\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    471\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m read \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\util.py:38\u001B[0m, in \u001B[0;36mreraise\u001B[1;34m(tp, value, tb)\u001B[0m\n\u001B[0;32m     37\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m value\u001B[38;5;241m.\u001B[39m__traceback__ \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m tb:\n\u001B[1;32m---> 38\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m value\u001B[38;5;241m.\u001B[39mwith_traceback(tb)\n\u001B[0;32m     39\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m value\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:793\u001B[0m, in \u001B[0;36mHTTPConnectionPool.urlopen\u001B[1;34m(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)\u001B[0m\n\u001B[0;32m    792\u001B[0m \u001B[38;5;66;03m# Make the request on the HTTPConnection object\u001B[39;00m\n\u001B[1;32m--> 793\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_make_request(\n\u001B[0;32m    794\u001B[0m     conn,\n\u001B[0;32m    795\u001B[0m     method,\n\u001B[0;32m    796\u001B[0m     url,\n\u001B[0;32m    797\u001B[0m     timeout\u001B[38;5;241m=\u001B[39mtimeout_obj,\n\u001B[0;32m    798\u001B[0m     body\u001B[38;5;241m=\u001B[39mbody,\n\u001B[0;32m    799\u001B[0m     headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m    800\u001B[0m     chunked\u001B[38;5;241m=\u001B[39mchunked,\n\u001B[0;32m    801\u001B[0m     retries\u001B[38;5;241m=\u001B[39mretries,\n\u001B[0;32m    802\u001B[0m     response_conn\u001B[38;5;241m=\u001B[39mresponse_conn,\n\u001B[0;32m    803\u001B[0m     preload_content\u001B[38;5;241m=\u001B[39mpreload_content,\n\u001B[0;32m    804\u001B[0m     decode_content\u001B[38;5;241m=\u001B[39mdecode_content,\n\u001B[0;32m    805\u001B[0m     \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mresponse_kw,\n\u001B[0;32m    806\u001B[0m )\n\u001B[0;32m    808\u001B[0m \u001B[38;5;66;03m# Everything went great!\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:491\u001B[0m, in \u001B[0;36mHTTPConnectionPool._make_request\u001B[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001B[0m\n\u001B[0;32m    490\u001B[0m         new_e \u001B[38;5;241m=\u001B[39m _wrap_proxy_error(new_e, conn\u001B[38;5;241m.\u001B[39mproxy\u001B[38;5;241m.\u001B[39mscheme)\n\u001B[1;32m--> 491\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m new_e\n\u001B[0;32m    493\u001B[0m \u001B[38;5;66;03m# conn.request() calls http.client.*.request, not the method in\u001B[39;00m\n\u001B[0;32m    494\u001B[0m \u001B[38;5;66;03m# urllib3.request. It also calls makefile (recv) on the socket.\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:467\u001B[0m, in \u001B[0;36mHTTPConnectionPool._make_request\u001B[1;34m(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)\u001B[0m\n\u001B[0;32m    466\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[1;32m--> 467\u001B[0m     \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_validate_conn\u001B[49m\u001B[43m(\u001B[49m\u001B[43mconn\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    468\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (SocketTimeout, BaseSSLError) \u001B[38;5;28;01mas\u001B[39;00m e:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connectionpool.py:1099\u001B[0m, in \u001B[0;36mHTTPSConnectionPool._validate_conn\u001B[1;34m(self, conn)\u001B[0m\n\u001B[0;32m   1098\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m conn\u001B[38;5;241m.\u001B[39mis_closed:\n\u001B[1;32m-> 1099\u001B[0m     \u001B[43mconn\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mconnect\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1101\u001B[0m \u001B[38;5;66;03m# TODO revise this, see https://github.com/urllib3/urllib3/issues/2791\u001B[39;00m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connection.py:653\u001B[0m, in \u001B[0;36mHTTPSConnection.connect\u001B[1;34m(self)\u001B[0m\n\u001B[0;32m    651\u001B[0m server_hostname_rm_dot \u001B[38;5;241m=\u001B[39m server_hostname\u001B[38;5;241m.\u001B[39mrstrip(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m.\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m--> 653\u001B[0m sock_and_verified \u001B[38;5;241m=\u001B[39m \u001B[43m_ssl_wrap_socket_and_match_hostname\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    654\u001B[0m \u001B[43m    \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    655\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcert_reqs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcert_reqs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    656\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    657\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_minimum_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_minimum_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    658\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_maximum_version\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_maximum_version\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    659\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_certs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_certs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    660\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_dir\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_cert_dir\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    661\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_data\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mca_cert_data\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    662\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcert_file\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcert_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    663\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_file\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mkey_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    664\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_password\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mkey_password\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    665\u001B[0m \u001B[43m    \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname_rm_dot\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    666\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mssl_context\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    667\u001B[0m \u001B[43m    \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    668\u001B[0m \u001B[43m    \u001B[49m\u001B[43massert_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43massert_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    669\u001B[0m \u001B[43m    \u001B[49m\u001B[43massert_fingerprint\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43massert_fingerprint\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    670\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    671\u001B[0m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msock \u001B[38;5;241m=\u001B[39m sock_and_verified\u001B[38;5;241m.\u001B[39msocket\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\connection.py:806\u001B[0m, in \u001B[0;36m_ssl_wrap_socket_and_match_hostname\u001B[1;34m(sock, cert_reqs, ssl_version, ssl_minimum_version, ssl_maximum_version, cert_file, key_file, key_password, ca_certs, ca_cert_dir, ca_cert_data, assert_hostname, assert_fingerprint, server_hostname, ssl_context, tls_in_tls)\u001B[0m\n\u001B[0;32m    804\u001B[0m         server_hostname \u001B[38;5;241m=\u001B[39m normalized\n\u001B[1;32m--> 806\u001B[0m ssl_sock \u001B[38;5;241m=\u001B[39m \u001B[43mssl_wrap_socket\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    807\u001B[0m \u001B[43m    \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    808\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkeyfile\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mkey_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    809\u001B[0m \u001B[43m    \u001B[49m\u001B[43mcertfile\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcert_file\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    810\u001B[0m \u001B[43m    \u001B[49m\u001B[43mkey_password\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mkey_password\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    811\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_certs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_certs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    812\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_dir\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_cert_dir\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    813\u001B[0m \u001B[43m    \u001B[49m\u001B[43mca_cert_data\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mca_cert_data\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    814\u001B[0m \u001B[43m    \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    815\u001B[0m \u001B[43m    \u001B[49m\u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcontext\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    816\u001B[0m \u001B[43m    \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    817\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    819\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\ssl_.py:465\u001B[0m, in \u001B[0;36mssl_wrap_socket\u001B[1;34m(sock, keyfile, certfile, cert_reqs, ca_certs, server_hostname, ssl_version, ciphers, ssl_context, ca_cert_dir, key_password, ca_cert_data, tls_in_tls)\u001B[0m\n\u001B[0;32m    463\u001B[0m     \u001B[38;5;28;01mpass\u001B[39;00m\n\u001B[1;32m--> 465\u001B[0m ssl_sock \u001B[38;5;241m=\u001B[39m \u001B[43m_ssl_wrap_socket_impl\u001B[49m\u001B[43m(\u001B[49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontext\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mtls_in_tls\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    466\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m ssl_sock\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\urllib3\\util\\ssl_.py:509\u001B[0m, in \u001B[0;36m_ssl_wrap_socket_impl\u001B[1;34m(sock, ssl_context, tls_in_tls, server_hostname)\u001B[0m\n\u001B[0;32m    507\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m SSLTransport(sock, ssl_context, server_hostname)\n\u001B[1;32m--> 509\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[43mssl_context\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mwrap_socket\u001B[49m\u001B[43m(\u001B[49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:513\u001B[0m, in \u001B[0;36mSSLContext.wrap_socket\u001B[1;34m(self, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, session)\u001B[0m\n\u001B[0;32m    507\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mwrap_socket\u001B[39m(\u001B[38;5;28mself\u001B[39m, sock, server_side\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mFalse\u001B[39;00m,\n\u001B[0;32m    508\u001B[0m                 do_handshake_on_connect\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[0;32m    509\u001B[0m                 suppress_ragged_eofs\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m,\n\u001B[0;32m    510\u001B[0m                 server_hostname\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, session\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m    511\u001B[0m     \u001B[38;5;66;03m# SSLSocket class handles server_hostname encoding before it calls\u001B[39;00m\n\u001B[0;32m    512\u001B[0m     \u001B[38;5;66;03m# ctx._wrap_socket()\u001B[39;00m\n\u001B[1;32m--> 513\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43msslsocket_class\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_create\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    514\u001B[0m \u001B[43m        \u001B[49m\u001B[43msock\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msock\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    515\u001B[0m \u001B[43m        \u001B[49m\u001B[43mserver_side\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_side\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    516\u001B[0m \u001B[43m        \u001B[49m\u001B[43mdo_handshake_on_connect\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mdo_handshake_on_connect\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    517\u001B[0m \u001B[43m        \u001B[49m\u001B[43msuppress_ragged_eofs\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msuppress_ragged_eofs\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    518\u001B[0m \u001B[43m        \u001B[49m\u001B[43mserver_hostname\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mserver_hostname\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    519\u001B[0m \u001B[43m        \u001B[49m\u001B[43mcontext\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[0;32m    520\u001B[0m \u001B[43m        \u001B[49m\u001B[43msession\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43msession\u001B[49m\n\u001B[0;32m    521\u001B[0m \u001B[43m    \u001B[49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:1071\u001B[0m, in \u001B[0;36mSSLSocket._create\u001B[1;34m(cls, sock, server_side, do_handshake_on_connect, suppress_ragged_eofs, server_hostname, context, session)\u001B[0m\n\u001B[0;32m   1070\u001B[0m             \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mdo_handshake_on_connect should not be specified for non-blocking sockets\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m-> 1071\u001B[0m         \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdo_handshake\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1072\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (\u001B[38;5;167;01mOSError\u001B[39;00m, \u001B[38;5;167;01mValueError\u001B[39;00m):\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\ssl.py:1342\u001B[0m, in \u001B[0;36mSSLSocket.do_handshake\u001B[1;34m(self, block)\u001B[0m\n\u001B[0;32m   1341\u001B[0m         \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msettimeout(\u001B[38;5;28;01mNone\u001B[39;00m)\n\u001B[1;32m-> 1342\u001B[0m     \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_sslobj\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mdo_handshake\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m   1343\u001B[0m \u001B[38;5;28;01mfinally\u001B[39;00m:\n",
      "\u001B[1;31mProtocolError\u001B[0m: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))",
      "\nDuring handling of the above exception, another exception occurred:\n",
      "\u001B[1;31mConnectionError\u001B[0m                           Traceback (most recent call last)",
      "Cell \u001B[1;32mIn[34], line 3\u001B[0m\n\u001B[0;32m      1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mlangchain\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m hub\n\u001B[1;32m----> 3\u001B[0m prompt \u001B[38;5;241m=\u001B[39m \u001B[43mhub\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpull\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mhwchase17/openai-functions-agent\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m)\u001B[49m\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\langchain\\hub.py:86\u001B[0m, in \u001B[0;36mpull\u001B[1;34m(owner_repo_commit, api_url, api_key)\u001B[0m\n\u001B[0;32m     82\u001B[0m client \u001B[38;5;241m=\u001B[39m _get_client(api_url\u001B[38;5;241m=\u001B[39mapi_url, api_key\u001B[38;5;241m=\u001B[39mapi_key)\n\u001B[0;32m     84\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mhasattr\u001B[39m(client, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mpull_repo\u001B[39m\u001B[38;5;124m\"\u001B[39m):\n\u001B[0;32m     85\u001B[0m     \u001B[38;5;66;03m# >= 0.1.15\u001B[39;00m\n\u001B[1;32m---> 86\u001B[0m     res_dict \u001B[38;5;241m=\u001B[39m \u001B[43mclient\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mpull_repo\u001B[49m\u001B[43m(\u001B[49m\u001B[43mowner_repo_commit\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m     87\u001B[0m     obj \u001B[38;5;241m=\u001B[39m loads(json\u001B[38;5;241m.\u001B[39mdumps(res_dict[\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mmanifest\u001B[39m\u001B[38;5;124m\"\u001B[39m]))\n\u001B[0;32m     88\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(obj, BasePromptTemplate):\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\langchainhub\\client.py:255\u001B[0m, in \u001B[0;36mClient.pull_repo\u001B[1;34m(self, owner_repo_commit)\u001B[0m\n\u001B[0;32m    253\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m commit_hash \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m    254\u001B[0m         \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNo commits found\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m--> 255\u001B[0m res \u001B[38;5;241m=\u001B[39m \u001B[43mrequests\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\n\u001B[0;32m    256\u001B[0m \u001B[43m    \u001B[49m\u001B[38;5;124;43mf\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_url\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m/commits/\u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mowner\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m/\u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mrepo\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m/\u001B[39;49m\u001B[38;5;132;43;01m{\u001B[39;49;00m\u001B[43mcommit_hash\u001B[49m\u001B[38;5;132;43;01m}\u001B[39;49;00m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[0;32m    257\u001B[0m \u001B[43m    \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m_get_headers\u001B[49m\u001B[43m(\u001B[49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[0;32m    258\u001B[0m \u001B[43m\u001B[49m\u001B[43m)\u001B[49m\n\u001B[0;32m    259\u001B[0m res\u001B[38;5;241m.\u001B[39mraise_for_status()\n\u001B[0;32m    260\u001B[0m result \u001B[38;5;241m=\u001B[39m res\u001B[38;5;241m.\u001B[39mjson()\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\api.py:73\u001B[0m, in \u001B[0;36mget\u001B[1;34m(url, params, **kwargs)\u001B[0m\n\u001B[0;32m     62\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mget\u001B[39m(url, params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs):\n\u001B[0;32m     63\u001B[0m \u001B[38;5;250m    \u001B[39m\u001B[38;5;124mr\u001B[39m\u001B[38;5;124;03m\"\"\"Sends a GET request.\u001B[39;00m\n\u001B[0;32m     64\u001B[0m \n\u001B[0;32m     65\u001B[0m \u001B[38;5;124;03m    :param url: URL for the new :class:`Request` object.\u001B[39;00m\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m     70\u001B[0m \u001B[38;5;124;03m    :rtype: requests.Response\u001B[39;00m\n\u001B[0;32m     71\u001B[0m \u001B[38;5;124;03m    \"\"\"\u001B[39;00m\n\u001B[1;32m---> 73\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m request(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mget\u001B[39m\u001B[38;5;124m\"\u001B[39m, url, params\u001B[38;5;241m=\u001B[39mparams, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\api.py:59\u001B[0m, in \u001B[0;36mrequest\u001B[1;34m(method, url, **kwargs)\u001B[0m\n\u001B[0;32m     55\u001B[0m \u001B[38;5;66;03m# By using the 'with' statement we are sure the session is closed, thus we\u001B[39;00m\n\u001B[0;32m     56\u001B[0m \u001B[38;5;66;03m# avoid leaving sockets open which can trigger a ResourceWarning in some\u001B[39;00m\n\u001B[0;32m     57\u001B[0m \u001B[38;5;66;03m# cases, and look like a memory leak in others.\u001B[39;00m\n\u001B[0;32m     58\u001B[0m \u001B[38;5;28;01mwith\u001B[39;00m sessions\u001B[38;5;241m.\u001B[39mSession() \u001B[38;5;28;01mas\u001B[39;00m session:\n\u001B[1;32m---> 59\u001B[0m     \u001B[38;5;28;01mreturn\u001B[39;00m session\u001B[38;5;241m.\u001B[39mrequest(method\u001B[38;5;241m=\u001B[39mmethod, url\u001B[38;5;241m=\u001B[39murl, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\sessions.py:589\u001B[0m, in \u001B[0;36mSession.request\u001B[1;34m(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)\u001B[0m\n\u001B[0;32m    584\u001B[0m send_kwargs \u001B[38;5;241m=\u001B[39m {\n\u001B[0;32m    585\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mtimeout\u001B[39m\u001B[38;5;124m\"\u001B[39m: timeout,\n\u001B[0;32m    586\u001B[0m     \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mallow_redirects\u001B[39m\u001B[38;5;124m\"\u001B[39m: allow_redirects,\n\u001B[0;32m    587\u001B[0m }\n\u001B[0;32m    588\u001B[0m send_kwargs\u001B[38;5;241m.\u001B[39mupdate(settings)\n\u001B[1;32m--> 589\u001B[0m resp \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39msend(prep, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39msend_kwargs)\n\u001B[0;32m    591\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m resp\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\sessions.py:703\u001B[0m, in \u001B[0;36mSession.send\u001B[1;34m(self, request, **kwargs)\u001B[0m\n\u001B[0;32m    700\u001B[0m start \u001B[38;5;241m=\u001B[39m preferred_clock()\n\u001B[0;32m    702\u001B[0m \u001B[38;5;66;03m# Send the request\u001B[39;00m\n\u001B[1;32m--> 703\u001B[0m r \u001B[38;5;241m=\u001B[39m adapter\u001B[38;5;241m.\u001B[39msend(request, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n\u001B[0;32m    705\u001B[0m \u001B[38;5;66;03m# Total elapsed time of the request (approximately)\u001B[39;00m\n\u001B[0;32m    706\u001B[0m elapsed \u001B[38;5;241m=\u001B[39m preferred_clock() \u001B[38;5;241m-\u001B[39m start\n",
      "File \u001B[1;32mD:\\Program Files (x86)\\python3\\lib\\site-packages\\requests\\adapters.py:501\u001B[0m, in \u001B[0;36mHTTPAdapter.send\u001B[1;34m(self, request, stream, timeout, verify, cert, proxies)\u001B[0m\n\u001B[0;32m    486\u001B[0m     resp \u001B[38;5;241m=\u001B[39m conn\u001B[38;5;241m.\u001B[39murlopen(\n\u001B[0;32m    487\u001B[0m         method\u001B[38;5;241m=\u001B[39mrequest\u001B[38;5;241m.\u001B[39mmethod,\n\u001B[0;32m    488\u001B[0m         url\u001B[38;5;241m=\u001B[39murl,\n\u001B[1;32m   (...)\u001B[0m\n\u001B[0;32m    497\u001B[0m         chunked\u001B[38;5;241m=\u001B[39mchunked,\n\u001B[0;32m    498\u001B[0m     )\n\u001B[0;32m    500\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m (ProtocolError, \u001B[38;5;167;01mOSError\u001B[39;00m) \u001B[38;5;28;01mas\u001B[39;00m err:\n\u001B[1;32m--> 501\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mConnectionError\u001B[39;00m(err, request\u001B[38;5;241m=\u001B[39mrequest)\n\u001B[0;32m    503\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m MaxRetryError \u001B[38;5;28;01mas\u001B[39;00m e:\n\u001B[0;32m    504\u001B[0m     \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28misinstance\u001B[39m(e\u001B[38;5;241m.\u001B[39mreason, ConnectTimeoutError):\n\u001B[0;32m    505\u001B[0m         \u001B[38;5;66;03m# TODO: Remove this in 3.0.0: see #2811\u001B[39;00m\n",
      "\u001B[1;31mConnectionError\u001B[0m: ('Connection aborted.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))"
     ]
    }
   ],
   "source": [
    "from langchain import hub\n",
    "\n",
    "prompt = hub.pull(\"hwchase17/openai-functions-agent\")"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from langchain.agents import create_openai_functions_agent\n",
    "\n",
    "agent = create_openai_functions_agent(llm, tools, prompt)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "from langchain.agents import AgentExecutor\n",
    "\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)"
   ],
   "metadata": {
    "collapsed": false
   }
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "outputs": [],
   "source": [
    "question = \"What is the product of the 998th, 999th and 1000th prime numbers?\"\n",
    "\n",
    "for step in agent_executor.iter({\"input\": question}):\n",
    "    if output := step.get(\"intermediate_step\"):\n",
    "        action, value = output[0]\n",
    "        if action.tool == \"GetPrime\":\n",
    "            print(f\"Checking whether {value} is prime...\")\n",
    "            assert is_prime(int(value))\n",
    "        # Ask user if they want to continue\n",
    "        _continue = input(\"Should the agent continue (Y/n)?:\\n\") or \"Y\"\n",
    "        if _continue.lower() != \"y\":\n",
    "            break"
   ],
   "metadata": {
    "collapsed": false
   }
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
